package Linux五种IO模型;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author coderFu
 * @create 2022/3/5
 * java NIO server
 *
 * channel Selector  Buffer
 *
 * 服务端channel 和客户端channel
 *
 * 服务端只有启动的时候有一个channel
 * 客户端每启动一个就有一个channel ，服务端维护客户端的channel
 *
 * Buffer
 * 三要素， 分配内存 allocate   capacity 容量 申请一个容量
 * channel 中的数据可以写到 buffer中 ， buffer中的数据可以写到
 * channel 中， limit 最大可以写入的量，或者最大可以读取的量
 * position 在写模式中 表示 当前写入的位置， flip（）调用后
 * position 会被置为0
 * limit 和 position 共同完成这写入和读取模式
 *
 * 使用完 buffer 后 要记得清除， 当缓冲区满了就无法写入数据了
 * clear（） compact（） 清除缓冲区， 一个是清除已读的内容
 * *
 *
 * scatter（分散）  gather（聚集聚合合并）
 */
public class NioServer {

    // 三要素：  channel Selector buffer

    public static void main(String[] args) throws IOException {

        // 开启服务端的通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        // 设置服务端端口
        serverSocketChannel.bind(new InetSocketAddress(8099));
        System.out.println("服务端端口为："+serverSocketChannel.getLocalAddress());

        // 获取一个Selector对象
        try (Selector selector = Selector.open()) {
            // 注册到 selector 中
          serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

          // 新建一个缓冲区 1024
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            // 不断接收链接
            while (true){
                // 阻塞 等待客户端建立链接，或者客户端输入时才能通过
                int select = selector.select();
                if (0 == select){
                    continue;
                }
                // 得到一个SelectKey集合
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                // 获取迭代器
                Iterator<SelectionKey> iterator = selectionKeys.iterator();

                while (iterator.hasNext()){
                    //  获取每一个key
                    SelectionKey key = iterator.next();
                    System.out.println("进来了几次？");
                    if (key.isAcceptable()){
                        ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                        // 客户端的channel
                        SocketChannel clientChannel = channel.accept();

                        System.out.println("客户端接口："+clientChannel.getRemoteAddress());
                        // 客户端设置为非阻塞
                        clientChannel.configureBlocking(false);

                        // 注册到 selector中
                        clientChannel.register(selector,SelectionKey.OP_READ);
                    }
                    if (key.isReadable()){

                        // 是可读的
                        SocketChannel channel = (SocketChannel) key.channel();
                        // 客户端的信息 读入 buffer里面的内容，客户端读入，
                        channel.read(byteBuffer);
                        String request = new String(byteBuffer.array()).trim();

                        // 情况 缓冲区
                        byteBuffer.clear();

                        System.out.println("客户端接口："+channel.getRemoteAddress()+"客户端输入:"+request);

                        String response = "server request"+request;
                        // 通过缓冲区 写出到 客户端
                        channel.write(ByteBuffer.wrap(response.getBytes()));
                    }
                    iterator.remove();
                }
            }
        }

    }
}
